﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;

namespace PacketRush.Core
{
    /// <summary>
    /// A collection of <see cref="T:PacketRush.Core.ClientInfo"/>
    /// </summary>
    internal class ClientInfoCollection : IList<ClientInfo>
    {
        private List<ClientInfo> _InternalList;
        private Dictionary<int, ClientInfo> _InternalIdKeyedDict;
        private Dictionary<EndPoint, ClientInfo> _InternalEndPointKeyedDict;

        public ClientInfoCollection(int initialCapacity, bool useIdDictLookup, bool useEndPointDictLookup)
        {
            _InternalList = new List<ClientInfo>(initialCapacity);
            if (useIdDictLookup) _InternalIdKeyedDict = new Dictionary<int, ClientInfo>(initialCapacity);
            if (useEndPointDictLookup) _InternalEndPointKeyedDict = new Dictionary<EndPoint, ClientInfo>(initialCapacity);
        }
        public int IndexOf(ClientInfo client)
        {
            return _InternalList.IndexOf(client);
        }

        public void Insert(int index, ClientInfo client)
        {
            if (_InternalIdKeyedDict != null) _InternalIdKeyedDict.Add(client.Connection.Id, client);
            if (_InternalEndPointKeyedDict != null) _InternalEndPointKeyedDict.Add(client.Connection.RemoteEndPoint, client);
            _InternalList.Insert(index, client);
        }

        public void RemoveAt(int index)
        {
            ClientInfo info = _InternalList[index];
            _InternalIdKeyedDict.Remove(info.Connection.Id);
            _InternalEndPointKeyedDict.Remove(info.Connection.RemoteEndPoint);
            _InternalList.RemoveAt(index);
        }

        public ClientInfo this[int index]
        {
            get
            {
                return _InternalList[index];
            }
            set
            {
                _InternalList[index] = value;
            }
        }

        public void Add(ClientInfo client)
        {
            if (_InternalIdKeyedDict != null) _InternalIdKeyedDict.Add(client.Connection.Id, client);
            if (_InternalEndPointKeyedDict != null) _InternalEndPointKeyedDict.Add(client.Connection.RemoteEndPoint, client);
            _InternalList.Add(client);
        }

        public void Clear()
        {
            if (_InternalIdKeyedDict != null) _InternalIdKeyedDict.Clear();
            if (_InternalEndPointKeyedDict != null) _InternalEndPointKeyedDict.Clear();
            _InternalList.Clear();
        }

        public bool Contains(ClientInfo client)
        {
            return _InternalList.Contains(client);
        }

        public void CopyTo(ClientInfo[] array, int arrayIndex)
        {
            _InternalList.CopyTo(array, arrayIndex);
        }

        public int Count
        {
            get { return _InternalList.Count; }
        }

        public bool IsReadOnly
        {
            get { return false; }
        }

        public bool Remove(ClientInfo client)
        {
            if (_InternalIdKeyedDict != null) _InternalIdKeyedDict.Remove(client.Connection.Id);
            if (_InternalEndPointKeyedDict != null) _InternalEndPointKeyedDict.Remove(client.Connection.RemoteEndPoint);

            return _InternalList.Remove(client);
        }

        public IEnumerator<ClientInfo> GetEnumerator()
        {
            return _InternalList.GetEnumerator();
        }

        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            return _InternalList.GetEnumerator();
        }

        public ClientInfo GetById(int clientConnectionId)
        {
            if (_InternalIdKeyedDict == null)
            {
                _InternalList.Find((client) => client.Connection.Id == clientConnectionId);
            }
            else
            {
                if (_InternalIdKeyedDict.ContainsKey(clientConnectionId))
                {
                    return _InternalIdKeyedDict[clientConnectionId];
                }
            }

            return null;
        }

        public ClientInfo GetByRemoteEndPoint(EndPoint endPoint)
        {
            if (_InternalEndPointKeyedDict == null)
            {
                return _InternalList.Find((client) => client.Connection.RemoteEndPoint.Equals(endPoint));
            }
            else
            {
                if (_InternalEndPointKeyedDict.ContainsKey(endPoint))
                {
                    return _InternalEndPointKeyedDict[endPoint];
                }
            }

            return null;
        }
    }
}
